<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="soulzookeeper">
      Soul网关源码解析（二十七）Zookeeper注册中心
     </h1>
     <hr/>
     <h2 id="_1">
      简介
     </h2>
     <p>
      本篇将详细介绍Zookeeper注册中心的的相关代码
     </p>
     <h2 id="_2">
      概要
     </h2>
     <p>
      服务发现中有两个角色：Provider、Consumer
     </p>
     <p>
      对应Soul网关里面就是Soul-Register-Center-Client、Soul-Register-Center-Server
     </p>
     <p>
      register-client在Soul-Client中被调用，也就是需要的接入的后台服务中使用该模块
     </p>
     <p>
      register-server在Soul-Admin中被调用，使用 Watch 等机制监听数据变化，进行相应的处理
     </p>
     <p>
      下面来看看register-client是如何将需要接入的服务接口信息放入Zookeeper中和register-server如何监听获取数据处理
     </p>
     <h2 id="register-client">
      Register-Client解析
     </h2>
     <h3 id="_3">
      示例运行
     </h3>
     <p>
      前面说过register-client在后台服务中使用，我们这里启动HTTP示例：soul-examples-http
     </p>
     <p>
      修改配置注册方式为zookeeper，并填写zookeeper的服务地址：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nt">soul</span><span class="p">:</span>
  <span class="nt">client</span><span class="p">:</span>
    <span class="nt">registerType</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">zookeeper</span>
    <span class="nt">serverLists</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">localhost:2181</span>
</code></pre>
     </div>
     <p>
      对了，确保自己运行了Zookeeper
     </p>
     <h3 id="_4">
      源码跟踪
     </h3>
     <p>
      在soul-examples-http中，我们看到是使用的注解进行服务接口信息注册的，大致如下：SoulSpringMvcClient
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@RestController</span>
<span class="nd">@RequestMapping</span><span class="p">(</span><span class="s">"/test"</span><span class="p">)</span>
<span class="nd">@SoulSpringMvcClient</span><span class="p">(</span><span class="n">path</span> <span class="o">=</span> <span class="s">"/test/**"</span><span class="p">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HttpTestController</span> <span class="p">{</span>

    <span class="nd">@PostMapping</span><span class="p">(</span><span class="s">"/payment"</span><span class="p">)</span>
    <span class="kd">public</span> <span class="n">UserDTO</span> <span class="nf">post</span><span class="p">(</span><span class="nd">@RequestBody</span> <span class="kd">final</span> <span class="n">UserDTO</span> <span class="n">userDTO</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">userDTO</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      注册的原理是实现Spring的BeanPostProcessor接口，对Bean进行自己的定制化操作，代码大致如下：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@Slf4j</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SpringMvcClientBeanPostProcessor</span> <span class="kd">implements</span> <span class="n">BeanPostProcessor</span> <span class="p">{</span>

    <span class="c1">// Distrupt publisher:用于将服务接口信息放入distrupt队列中</span>
    <span class="kd">private</span> <span class="n">SoulClientRegisterEventPublisher</span> <span class="n">publisher</span> <span class="o">=</span> <span class="n">SoulClientRegisterEventPublisher</span><span class="p">.</span><span class="na">getInstance</span><span class="p">();</span>

    <span class="kd">public</span> <span class="nf">SpringMvcClientBeanPostProcessor</span><span class="p">(</span><span class="kd">final</span> <span class="n">SoulRegisterCenterConfig</span> <span class="n">config</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 一推的获取配置信息的代码，省略</span>
        <span class="p">......</span>
        <span class="c1">// 这里使用SPI机制进行对应的注册中心的加载初始化和Distrupt的初始化</span>
        <span class="c1">// 可以参考:SPI全解析(https://blog.csdn.net/zm469568595/article/details/113362044)</span>
        <span class="n">SoulClientRegisterRepository</span> <span class="n">soulClientRegisterRepository</span> <span class="o">=</span> <span class="n">SoulClientRegisterRepositoryFactory</span><span class="p">.</span><span class="na">newInstance</span><span class="p">(</span><span class="n">config</span><span class="p">);</span>
        <span class="n">publisher</span><span class="p">.</span><span class="na">start</span><span class="p">(</span><span class="n">soulClientRegisterRepository</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">Object</span> <span class="nf">postProcessAfterInitialization</span><span class="p">(</span><span class="nd">@NonNull</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">bean</span><span class="p">,</span> <span class="nd">@NonNull</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">beanName</span><span class="p">)</span> <span class="kd">throws</span> <span class="n">BeansException</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">isFull</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">bean</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">Controller</span> <span class="n">controller</span> <span class="o">=</span> <span class="n">AnnotationUtils</span><span class="p">.</span><span class="na">findAnnotation</span><span class="p">(</span><span class="n">bean</span><span class="p">.</span><span class="na">getClass</span><span class="p">(),</span> <span class="n">Controller</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="n">RequestMapping</span> <span class="n">requestMapping</span> <span class="o">=</span> <span class="n">AnnotationUtils</span><span class="p">.</span><span class="na">findAnnotation</span><span class="p">(</span><span class="n">bean</span><span class="p">.</span><span class="na">getClass</span><span class="p">(),</span> <span class="n">RequestMapping</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">controller</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">requestMapping</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
            <span class="c1">// 这里通过判断是否具有soul的特定注解：SoulSpringMvcClient，有的话进行服务注册</span>
            <span class="c1">// MVC有通配机制，这里就不详解了</span>
            <span class="n">SoulSpringMvcClient</span> <span class="n">clazzAnnotation</span> <span class="o">=</span> <span class="n">AnnotationUtils</span><span class="p">.</span><span class="na">findAnnotation</span><span class="p">(</span><span class="n">bean</span><span class="p">.</span><span class="na">getClass</span><span class="p">(),</span> <span class="n">SoulSpringMvcClient</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
            <span class="p">......</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">clazzAnnotation</span><span class="p">.</span><span class="na">path</span><span class="p">().</span><span class="na">indexOf</span><span class="p">(</span><span class="s">"*"</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">String</span> <span class="n">finalPrePath</span> <span class="o">=</span> <span class="n">prePath</span><span class="p">;</span>
                <span class="c1">// 这里将注册信息放入Distrupt中</span>
                <span class="c1">// Distrupt有点类似消息队列</span>
                <span class="n">executorService</span><span class="p">.</span><span class="na">execute</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="n">publisher</span><span class="p">.</span><span class="na">publishEvent</span><span class="p">(</span><span class="n">buildMetaDataDTO</span><span class="p">(</span><span class="n">clazzAnnotation</span><span class="p">,</span> <span class="n">finalPrePath</span><span class="p">)));</span>
                <span class="k">return</span> <span class="n">bean</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="p">......</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">bean</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      在上面的分析中看到了将服务信息放入Distrupt，下面来看看 SoulClientRegisterEventPublisher 的相关代码：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">SoulClientRegisterEventPublisher</span> <span class="p">{</span>

    <span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">publishEvent</span><span class="p">(</span><span class="kd">final</span> <span class="n">T</span> <span class="n">data</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">DisruptorProvider</span><span class="o">&lt;</span><span class="n">Object</span><span class="o">&gt;</span> <span class="n">provider</span> <span class="o">=</span> <span class="n">providerManage</span><span class="p">.</span><span class="na">getProvider</span><span class="p">();</span>
        <span class="c1">// 将数据放入队列中</span>
        <span class="n">provider</span><span class="p">.</span><span class="na">onData</span><span class="p">(</span><span class="n">f</span> <span class="o">-&gt;</span> <span class="n">f</span><span class="p">.</span><span class="na">setData</span><span class="p">(</span><span class="n">data</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      通过上面的代码，我们大致能猜到这是一个producer/consumer的模式，下面我们看看consumer相关的类代码：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@SuppressWarnings</span><span class="p">(</span><span class="s">"all"</span><span class="p">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">RegisterClientConsumerExecutor</span> <span class="kd">extends</span> <span class="n">QueueConsumerExecutor</span><span class="o">&lt;</span><span class="n">DataTypeParent</span><span class="o">&gt;</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// 看到在这取出队列中的数据，并调用处理逻辑</span>
        <span class="n">DataTypeParent</span> <span class="n">result</span> <span class="o">=</span> <span class="n">getData</span><span class="p">();</span>
        <span class="n">executorSubscriber</span><span class="p">.</span><span class="na">executor</span><span class="p">(</span><span class="n">Lists</span><span class="p">.</span><span class="na">newArrayList</span><span class="p">(</span><span class="n">result</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      跟着看看（进行调试即可跟进去）
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">SoulClientMetadataExecutorSubscriber</span> <span class="kd">implements</span> <span class="n">ExecutorTypeSubscriber</span><span class="o">&lt;</span><span class="n">MetaDataRegisterDTO</span><span class="o">&gt;</span> <span class="p">{</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="n">SoulClientRegisterRepository</span> <span class="n">soulClientRegisterRepository</span><span class="p">;</span>

    <span class="cm">/**</span>
<span class="cm">     * Instantiates a new Soul client metadata executor subscriber.</span>
<span class="cm">     *</span>
<span class="cm">     * @param soulClientRegisterRepository the soul client register repository</span>
<span class="cm">     */</span>
    <span class="kd">public</span> <span class="nf">SoulClientMetadataExecutorSubscriber</span><span class="p">(</span><span class="kd">final</span> <span class="n">SoulClientRegisterRepository</span> <span class="n">soulClientRegisterRepository</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="na">soulClientRegisterRepository</span> <span class="o">=</span> <span class="n">soulClientRegisterRepository</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">DataType</span> <span class="nf">getType</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">DataType</span><span class="p">.</span><span class="na">META_DATA</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">executor</span><span class="p">(</span><span class="kd">final</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">MetaDataRegisterDTO</span><span class="o">&gt;</span> <span class="n">metaDataRegisterDTOList</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 在这里调用注册中心的相关处理逻辑对数据进行处理</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">MetaDataRegisterDTO</span> <span class="n">metaDataRegisterDTO</span> <span class="p">:</span> <span class="n">metaDataRegisterDTOList</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">soulClientRegisterRepository</span><span class="p">.</span><span class="na">persistInterface</span><span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      我们再跟到persistInterface函数中，发现来到了： ZookeeperClientRegisterRepository
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ZookeeperClientRegisterRepository</span> <span class="kd">implements</span> <span class="n">SoulClientRegisterRepository</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">persistInterface</span><span class="p">(</span><span class="kd">final</span> <span class="n">MetaDataRegisterDTO</span> <span class="n">metadata</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">rpcType</span> <span class="o">=</span> <span class="n">metadata</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">contextPath</span> <span class="o">=</span> <span class="n">metadata</span><span class="p">.</span><span class="na">getContextPath</span><span class="p">().</span><span class="na">substring</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
        <span class="c1">// 将服务接口数据写到Zookeeper节点中</span>
        <span class="n">registerMetadata</span><span class="p">(</span><span class="n">rpcType</span><span class="p">,</span> <span class="n">contextPath</span><span class="p">,</span> <span class="n">metadata</span><span class="p">);</span>
        <span class="c1">// 如果是http/tars/grpc，需要再写一份数据到uri节点下，用于进行服务的上下线</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">HTTP</span><span class="p">.</span><span class="na">getName</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">rpcType</span><span class="p">)</span> <span class="o">||</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">TARS</span><span class="p">.</span><span class="na">getName</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">rpcType</span><span class="p">)</span> <span class="o">||</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">GRPC</span><span class="p">.</span><span class="na">getName</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">rpcType</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">registerURI</span><span class="p">(</span><span class="n">rpcType</span><span class="p">,</span> <span class="n">contextPath</span><span class="p">,</span> <span class="n">metadata</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">log</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">"{} zookeeper client register success: {}"</span><span class="p">,</span> <span class="n">rpcType</span><span class="p">,</span> <span class="n">metadata</span><span class="p">.</span><span class="na">toString</span><span class="p">());</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      ZookeeperClientRegisterRepository 进行具体的Zookeeper信息写入，写入的数据结构如下：
     </p>
     <div class="codehilite">
      <pre><span></span><code>soul
   ├──regsiter
   ├    ├──metadata
   ├    ├     ├──<span class="cp">${</span><span class="n">rpcType</span><span class="cp">}</span>
   ├    ├     ├      ├────<span class="cp">${</span><span class="n">contextPath</span><span class="cp">}</span>
   ├    ├     ├               ├──<span class="cp">${</span><span class="n">ruleName</span><span class="cp">}</span> : save metadata data of MetaDataRegisterDTO
   ├    ├──uri
   ├    ├     ├──<span class="cp">${</span><span class="n">rpcType</span><span class="cp">}</span>
   ├    ├     ├      ├────<span class="cp">${</span><span class="n">contextPath</span><span class="cp">}</span>
   ├    ├     ├               ├──<span class="cp">${</span><span class="n">ip</span><span class="p">:</span><span class="n">prot</span><span class="cp">}</span> : save uri data of URIRegisterDTO
   ├    ├     ├               ├──<span class="cp">${</span><span class="n">ip</span><span class="p">:</span><span class="n">prot</span><span class="cp">}</span>
</code></pre>
     </div>
     <p>
      OK，到这Zookeeper相关的注册就写完了
     </p>
     <h2 id="register-server">
      Register-Server解析
     </h2>
     <h3 id="soul-admin">
      Soul-Admin运行
     </h3>
     <p>
      Register-Server相关服务是随着Soul-Admin运行的
     </p>
     <p>
      我们修改Soul-Admin的注册中心方式为Zookeeper，大致如下：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nt">soul</span><span class="p">:</span>
  <span class="nt">register</span><span class="p">:</span>
    <span class="nt">registerType</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">zookeeper</span>
    <span class="nt">serverLists </span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">localhost:2181</span>
</code></pre>
     </div>
     <h3 id="_5">
      源码解析
     </h3>
     <p>
      Register-Server的配置其中的文件如下：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@Slf4j</span>
<span class="nd">@Configuration</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">RegisterCenterConfiguration</span> <span class="p">{</span>

    <span class="nd">@Bean</span>
    <span class="kd">public</span> <span class="n">SoulServerRegisterRepository</span> <span class="nf">soulServerRegisterRepository</span><span class="p">(</span><span class="kd">final</span> <span class="n">SoulRegisterCenterConfig</span> <span class="n">soulRegisterCenterConfig</span><span class="p">,</span> 
                                                                     <span class="kd">final</span> <span class="n">SoulClientRegisterService</span> <span class="n">soulClientRegisterService</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">registerType</span> <span class="o">=</span> <span class="n">soulRegisterCenterConfig</span><span class="p">.</span><span class="na">getRegisterType</span><span class="p">();</span>
        <span class="c1">// 使用SPI进行相关注册中心的加载初始化</span>
        <span class="n">SoulServerRegisterRepository</span> <span class="n">registerRepository</span> <span class="o">=</span> <span class="n">ExtensionLoader</span><span class="p">.</span><span class="na">getExtensionLoader</span><span class="p">(</span><span class="n">SoulServerRegisterRepository</span><span class="p">.</span><span class="na">class</span><span class="p">).</span><span class="na">getJoin</span><span class="p">(</span><span class="n">registerType</span><span class="p">);</span>
        <span class="n">RegisterServerDisruptorPublisher</span> <span class="n">publisher</span> <span class="o">=</span> <span class="n">RegisterServerDisruptorPublisher</span><span class="p">.</span><span class="na">getInstance</span><span class="p">();</span>
        <span class="n">publisher</span><span class="p">.</span><span class="na">start</span><span class="p">(</span><span class="n">soulClientRegisterService</span><span class="p">);</span>
        <span class="n">registerRepository</span><span class="p">.</span><span class="na">init</span><span class="p">(</span><span class="n">publisher</span><span class="p">,</span> <span class="n">soulRegisterCenterConfig</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">registerRepository</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      跟着进去来到：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@Slf4j</span>
<span class="nd">@Join</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ZookeeperServerRegisterRepository</span> <span class="kd">implements</span> <span class="n">SoulServerRegisterRepository</span> <span class="p">{</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">EnumSet</span><span class="o">&lt;</span><span class="n">RpcTypeEnum</span><span class="o">&gt;</span> <span class="n">METADATA_SET</span> <span class="o">=</span> <span class="n">EnumSet</span><span class="p">.</span><span class="na">of</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">DUBBO</span><span class="p">,</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">GRPC</span><span class="p">,</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">HTTP</span><span class="p">,</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">SPRING_CLOUD</span><span class="p">,</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">SOFA</span><span class="p">,</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">TARS</span><span class="p">);</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">EnumSet</span><span class="o">&lt;</span><span class="n">RpcTypeEnum</span><span class="o">&gt;</span> <span class="n">URI_SET</span> <span class="o">=</span> <span class="n">EnumSet</span><span class="p">.</span><span class="na">of</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">GRPC</span><span class="p">,</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">HTTP</span><span class="p">,</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">TARS</span><span class="p">);</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">initSubscribe</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// 需要对Metadata和Uri进行监听</span>
        <span class="c1">// metadata 是具体服务注册信息，如selector和rules</span>
        <span class="c1">// uri 对应upstream，目的用于探活或者服务的上下线</span>
        <span class="n">METADATA_SET</span><span class="p">.</span><span class="na">forEach</span><span class="p">(</span><span class="n">rpcTypeEnum</span> <span class="o">-&gt;</span> <span class="n">subscribeMetaData</span><span class="p">(</span><span class="n">rpcTypeEnum</span><span class="p">.</span><span class="na">getName</span><span class="p">()));</span>
        <span class="n">URI_SET</span><span class="p">.</span><span class="na">forEach</span><span class="p">(</span><span class="n">rpcTypeEnum</span> <span class="o">-&gt;</span> <span class="n">subscribeURI</span><span class="p">(</span><span class="n">rpcTypeEnum</span><span class="p">.</span><span class="na">getName</span><span class="p">()));</span>
    <span class="p">}</span>

    <span class="c1">// 监听对应rpctype的uri目录</span>
    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">subscribeURI</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">rpcType</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">contextPathParent</span> <span class="o">=</span> <span class="n">RegisterPathConstants</span><span class="p">.</span><span class="na">buildURIContextPathParent</span><span class="p">(</span><span class="n">rpcType</span><span class="p">);</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">contextPaths</span> <span class="o">=</span> <span class="n">zkClientGetChildren</span><span class="p">(</span><span class="n">contextPathParent</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">String</span> <span class="n">contextPath</span> <span class="p">:</span> <span class="n">contextPaths</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">watcherURI</span><span class="p">(</span><span class="n">rpcType</span><span class="p">,</span> <span class="n">contextPath</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">zkClient</span><span class="p">.</span><span class="na">subscribeChildChanges</span><span class="p">(</span><span class="n">contextPathParent</span><span class="p">,</span> <span class="p">(</span><span class="n">parentPath</span><span class="p">,</span> <span class="n">currentChildren</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">currentChildren</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">for</span> <span class="p">(</span><span class="n">String</span> <span class="n">contextPath</span> <span class="p">:</span> <span class="n">currentChildren</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">watcherURI</span><span class="p">(</span><span class="n">rpcType</span><span class="p">,</span> <span class="n">contextPath</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">});</span>
    <span class="p">}</span>

   <span class="c1">// 监听对应rpctype的metadata目录</span>
    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">subscribeMetaData</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">rpcType</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">contextPathParent</span> <span class="o">=</span> <span class="n">RegisterPathConstants</span><span class="p">.</span><span class="na">buildMetaDataContextPathParent</span><span class="p">(</span><span class="n">rpcType</span><span class="p">);</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">contextPaths</span> <span class="o">=</span> <span class="n">zkClientGetChildren</span><span class="p">(</span><span class="n">contextPathParent</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">String</span> <span class="n">contextPath</span> <span class="p">:</span> <span class="n">contextPaths</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">watcherMetadata</span><span class="p">(</span><span class="n">rpcType</span><span class="p">,</span> <span class="n">contextPath</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">zkClient</span><span class="p">.</span><span class="na">subscribeChildChanges</span><span class="p">(</span><span class="n">contextPathParent</span><span class="p">,</span> <span class="p">(</span><span class="n">parentPath</span><span class="p">,</span> <span class="n">currentChildren</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">currentChildren</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">for</span> <span class="p">(</span><span class="n">String</span> <span class="n">contextPath</span> <span class="p">:</span> <span class="n">currentChildren</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">watcherMetadata</span><span class="p">(</span><span class="n">rpcType</span><span class="p">,</span> <span class="n">contextPath</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="c1">// 读取数据进行服务注册处理，并监听该目录，有数据变动时进行服务注册处理</span>
    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">watcherMetadata</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">rpcType</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">contextPath</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">metaDataParentPath</span> <span class="o">=</span> <span class="n">RegisterPathConstants</span><span class="p">.</span><span class="na">buildMetaDataParentPath</span><span class="p">(</span><span class="n">rpcType</span><span class="p">,</span> <span class="n">contextPath</span><span class="p">);</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">childrenList</span> <span class="o">=</span> <span class="n">zkClientGetChildren</span><span class="p">(</span><span class="n">metaDataParentPath</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">childrenList</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">childrenList</span><span class="p">.</span><span class="na">forEach</span><span class="p">(</span><span class="n">children</span> <span class="o">-&gt;</span> <span class="p">{</span>
                <span class="n">String</span> <span class="n">realPath</span> <span class="o">=</span> <span class="n">RegisterPathConstants</span><span class="p">.</span><span class="na">buildRealNode</span><span class="p">(</span><span class="n">metaDataParentPath</span><span class="p">,</span> <span class="n">children</span><span class="p">);</span>
                <span class="n">publishMetadata</span><span class="p">(</span><span class="n">zkClient</span><span class="p">.</span><span class="na">readData</span><span class="p">(</span><span class="n">realPath</span><span class="p">).</span><span class="na">toString</span><span class="p">());</span>
                <span class="n">subscribeMetaDataChanges</span><span class="p">(</span><span class="n">realPath</span><span class="p">);</span>
            <span class="p">});</span>
        <span class="p">}</span>
        <span class="n">zkClient</span><span class="p">.</span><span class="na">subscribeChildChanges</span><span class="p">(</span><span class="n">metaDataParentPath</span><span class="p">,</span> <span class="p">(</span><span class="n">parentPath</span><span class="p">,</span> <span class="n">currentChildren</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">currentChildren</span><span class="p">))</span> <span class="p">{</span>
                <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">addSubscribePath</span> <span class="o">=</span> <span class="n">addSubscribePath</span><span class="p">(</span><span class="n">childrenList</span><span class="p">,</span> <span class="n">currentChildren</span><span class="p">);</span>
                <span class="n">addSubscribePath</span><span class="p">.</span><span class="na">stream</span><span class="p">().</span><span class="na">map</span><span class="p">(</span><span class="n">addPath</span> <span class="o">-&gt;</span> <span class="p">{</span>
                    <span class="n">String</span> <span class="n">realPath</span> <span class="o">=</span> <span class="n">RegisterPathConstants</span><span class="p">.</span><span class="na">buildRealNode</span><span class="p">(</span><span class="n">parentPath</span><span class="p">,</span> <span class="n">addPath</span><span class="p">);</span>
                    <span class="n">publishMetadata</span><span class="p">(</span><span class="n">zkClient</span><span class="p">.</span><span class="na">readData</span><span class="p">(</span><span class="n">realPath</span><span class="p">).</span><span class="na">toString</span><span class="p">());</span>
                    <span class="k">return</span> <span class="n">realPath</span><span class="p">;</span>
                <span class="p">}).</span><span class="na">forEach</span><span class="p">(</span><span class="k">this</span><span class="p">::</span><span class="n">subscribeMetaDataChanges</span><span class="p">);</span>

            <span class="p">}</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">watcherURI</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">rpcType</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">contextPath</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">uriParentPath</span> <span class="o">=</span> <span class="n">RegisterPathConstants</span><span class="p">.</span><span class="na">buildURIParentPath</span><span class="p">(</span><span class="n">rpcType</span><span class="p">,</span> <span class="n">contextPath</span><span class="p">);</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">childrenList</span> <span class="o">=</span> <span class="n">zkClientGetChildren</span><span class="p">(</span><span class="n">uriParentPath</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">childrenList</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">registerURIChildrenList</span><span class="p">(</span><span class="n">childrenList</span><span class="p">,</span> <span class="n">uriParentPath</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">zkClient</span><span class="p">.</span><span class="na">subscribeChildChanges</span><span class="p">(</span><span class="n">uriParentPath</span><span class="p">,</span> <span class="p">(</span><span class="n">parentPath</span><span class="p">,</span> <span class="n">currentChildren</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">currentChildren</span><span class="p">))</span> <span class="p">{</span>
                <span class="n">registerURIChildrenList</span><span class="p">(</span><span class="n">currentChildren</span><span class="p">,</span> <span class="n">parentPath</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">registerURIChildrenList</span><span class="p">(</span><span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">(),</span> <span class="n">parentPath</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="c1">// 这里uri处理需要注意：传入的是当前的存在uri列表，如果为空需要传入构造一个空的uri数据</span>
    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">registerURIChildrenList</span><span class="p">(</span><span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">childrenList</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">uriParentPath</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">URIRegisterDTO</span><span class="o">&gt;</span> <span class="n">registerDTOList</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">();</span>
        <span class="n">childrenList</span><span class="p">.</span><span class="na">forEach</span><span class="p">(</span><span class="n">addPath</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="n">String</span> <span class="n">realPath</span> <span class="o">=</span> <span class="n">RegisterPathConstants</span><span class="p">.</span><span class="na">buildRealNode</span><span class="p">(</span><span class="n">uriParentPath</span><span class="p">,</span> <span class="n">addPath</span><span class="p">);</span>
            <span class="n">registerDTOList</span><span class="p">.</span><span class="na">add</span><span class="p">(</span><span class="n">GsonUtils</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">fromJson</span><span class="p">(</span><span class="n">zkClient</span><span class="p">.</span><span class="na">readData</span><span class="p">(</span><span class="n">realPath</span><span class="p">).</span><span class="na">toString</span><span class="p">(),</span> <span class="n">URIRegisterDTO</span><span class="p">.</span><span class="na">class</span><span class="p">));</span>
        <span class="p">});</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">registerDTOList</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">String</span> <span class="n">contextPath</span> <span class="o">=</span> <span class="n">StringUtils</span><span class="p">.</span><span class="na">substringAfterLast</span><span class="p">(</span><span class="n">uriParentPath</span><span class="p">,</span> <span class="s">"/"</span><span class="p">);</span>
            <span class="n">URIRegisterDTO</span> <span class="n">uriRegisterDTO</span> <span class="o">=</span> <span class="n">URIRegisterDTO</span><span class="p">.</span><span class="na">builder</span><span class="p">().</span><span class="na">contextPath</span><span class="p">(</span><span class="s">"/"</span> <span class="o">+</span> <span class="n">contextPath</span><span class="p">).</span><span class="na">build</span><span class="p">();</span>
            <span class="n">registerDTOList</span><span class="p">.</span><span class="na">add</span><span class="p">(</span><span class="n">uriRegisterDTO</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">publishRegisterURI</span><span class="p">(</span><span class="n">registerDTOList</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">subscribeMetaDataChanges</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">realPath</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">zkClient</span><span class="p">.</span><span class="na">subscribeDataChanges</span><span class="p">(</span><span class="n">realPath</span><span class="p">,</span> <span class="k">new</span> <span class="n">IZkDataListener</span><span class="p">()</span> <span class="p">{</span>
            <span class="nd">@Override</span>
            <span class="kd">public</span> <span class="kt">void</span> <span class="nf">handleDataChange</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">dataPath</span><span class="p">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">data</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">publishMetadata</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="na">toString</span><span class="p">());</span>
            <span class="p">}</span>

            <span class="nd">@SneakyThrows</span>
            <span class="nd">@Override</span>
            <span class="kd">public</span> <span class="kt">void</span> <span class="nf">handleDataDeleted</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">dataPath</span><span class="p">)</span> <span class="p">{</span>

            <span class="p">}</span>
        <span class="p">});</span>
    <span class="p">}</span>

    <span class="c1">// 将metadata注册信息放入distrupt队列中</span>
    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">publishMetadata</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">data</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">publisher</span><span class="p">.</span><span class="na">publish</span><span class="p">(</span><span class="n">Lists</span><span class="p">.</span><span class="na">newArrayList</span><span class="p">(</span><span class="n">GsonUtils</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">fromJson</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">MetaDataRegisterDTO</span><span class="p">.</span><span class="na">class</span><span class="p">)));</span>
    <span class="p">}</span>

    <span class="c1">// 将uri注册信息放入distrupt队列中</span>
    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">publishRegisterURI</span><span class="p">(</span><span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">URIRegisterDTO</span><span class="o">&gt;</span> <span class="n">registerDTOList</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">publisher</span><span class="p">.</span><span class="na">publish</span><span class="p">(</span><span class="n">registerDTOList</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      从上面的代码中，我们看到了Zookeeper如何取监听和取数据进行处理
     </p>
     <p>
      下面我们跟着看看，数据如何进行处理的，相关的distrupt代码类似Soul-Client那边的：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">RegisterServerDisruptorPublisher</span> <span class="kd">implements</span> <span class="n">SoulServerRegisterPublisher</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">publish</span><span class="p">(</span><span class="kd">final</span> <span class="n">T</span> <span class="n">data</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">DisruptorProvider</span><span class="o">&lt;</span><span class="n">Object</span><span class="o">&gt;</span> <span class="n">provider</span> <span class="o">=</span> <span class="n">providerManage</span><span class="p">.</span><span class="na">getProvider</span><span class="p">();</span>
        <span class="c1">// 数据放入队列</span>
        <span class="n">provider</span><span class="p">.</span><span class="na">onData</span><span class="p">(</span><span class="n">f</span> <span class="o">-&gt;</span> <span class="n">f</span><span class="p">.</span><span class="na">setData</span><span class="p">(</span><span class="n">data</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">RegisterServerConsumerExecutor</span> <span class="kd">extends</span> <span class="n">QueueConsumerExecutor</span><span class="o">&lt;</span><span class="n">List</span><span class="o">&lt;</span><span class="n">DataTypeParent</span><span class="o">&gt;&gt;</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// 获取数据，根据是metadata或者uri调用不同的处理逻辑</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">DataTypeParent</span><span class="o">&gt;</span> <span class="n">results</span> <span class="o">=</span> <span class="n">getData</span><span class="p">();</span>
        <span class="n">getType</span><span class="p">(</span><span class="n">results</span><span class="p">).</span><span class="na">executor</span><span class="p">(</span><span class="n">results</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">ExecutorSubscriber</span> <span class="nf">getType</span><span class="p">(</span><span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">DataTypeParent</span><span class="o">&gt;</span> <span class="n">list</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">list</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">list</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">())</span> <span class="p">{</span>
            <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">DataTypeParent</span> <span class="n">result</span> <span class="o">=</span> <span class="n">list</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">subscribers</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="na">getType</span><span class="p">());</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      metadata处理逻辑如下，大致是调用相应的注册服务即可：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MetadataExecutorSubscriber</span> <span class="kd">implements</span> <span class="n">ExecutorTypeSubscriber</span><span class="o">&lt;</span><span class="n">MetaDataRegisterDTO</span><span class="o">&gt;</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">executor</span><span class="p">(</span><span class="kd">final</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">MetaDataRegisterDTO</span><span class="o">&gt;</span> <span class="n">metaDataRegisterDTOList</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">MetaDataRegisterDTO</span> <span class="n">metaDataRegisterDTO</span> <span class="p">:</span> <span class="n">metaDataRegisterDTOList</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">DUBBO</span><span class="p">.</span><span class="na">getName</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">soulClientRegisterService</span><span class="p">.</span><span class="na">registerDubbo</span><span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">SOFA</span><span class="p">.</span><span class="na">getName</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">soulClientRegisterService</span><span class="p">.</span><span class="na">registerSofa</span><span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">TARS</span><span class="p">.</span><span class="na">getName</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">soulClientRegisterService</span><span class="p">.</span><span class="na">registerTars</span><span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">HTTP</span><span class="p">.</span><span class="na">getName</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">soulClientRegisterService</span><span class="p">.</span><span class="na">registerSpringMvc</span><span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">SPRING_CLOUD</span><span class="p">.</span><span class="na">getName</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">soulClientRegisterService</span><span class="p">.</span><span class="na">registerSpringCloud</span><span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">.</span><span class="na">getRpcType</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">GRPC</span><span class="p">.</span><span class="na">getName</span><span class="p">()))</span> <span class="p">{</span>
                <span class="n">soulClientRegisterService</span><span class="p">.</span><span class="na">registerGrpc</span><span class="p">(</span><span class="n">metaDataRegisterDTO</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      uri处理逻辑，根据数据构造好相应的upstream列表数据，调用相应的处理逻辑即可：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">URIRegisterExecutorSubscriber</span> <span class="kd">implements</span> <span class="n">ExecutorTypeSubscriber</span><span class="o">&lt;</span><span class="n">URIRegisterDTO</span><span class="o">&gt;</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">executor</span><span class="p">(</span><span class="kd">final</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">URIRegisterDTO</span><span class="o">&gt;</span> <span class="n">dataList</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">URIRegisterDTO</span><span class="o">&gt;&gt;</span> <span class="n">listMap</span> <span class="o">=</span> <span class="n">dataList</span><span class="p">.</span><span class="na">stream</span><span class="p">().</span><span class="na">collect</span><span class="p">(</span><span class="n">Collectors</span><span class="p">.</span><span class="na">groupingBy</span><span class="p">(</span><span class="n">URIRegisterDTO</span><span class="p">::</span><span class="n">getContextPath</span><span class="p">));</span>
        <span class="n">listMap</span><span class="p">.</span><span class="na">forEach</span><span class="p">((</span><span class="n">contextPath</span><span class="p">,</span> <span class="n">dtoList</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">uriList</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">();</span>
            <span class="n">dataList</span><span class="p">.</span><span class="na">forEach</span><span class="p">(</span><span class="n">uriRegisterDTO</span> <span class="o">-&gt;</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">uriRegisterDTO</span><span class="p">.</span><span class="na">getHost</span><span class="p">()</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">uriRegisterDTO</span><span class="p">.</span><span class="na">getPort</span><span class="p">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">uriList</span><span class="p">.</span><span class="na">add</span><span class="p">(</span><span class="n">String</span><span class="p">.</span><span class="na">join</span><span class="p">(</span><span class="s">":"</span><span class="p">,</span> <span class="n">uriRegisterDTO</span><span class="p">.</span><span class="na">getHost</span><span class="p">(),</span> <span class="n">uriRegisterDTO</span><span class="p">.</span><span class="na">getPort</span><span class="p">().</span><span class="na">toString</span><span class="p">()));</span>
                <span class="p">}</span>
            <span class="p">});</span>
            <span class="n">soulClientRegisterService</span><span class="p">.</span><span class="na">registerURI</span><span class="p">(</span><span class="n">contextPath</span><span class="p">,</span> <span class="n">uriList</span><span class="p">);</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      下面的就是Service层面的操作，更新数据库，发布数据同步事件，这里就不详细说了，前面的文章中有相关的
     </p>
     <h2 id="_6">
      总结
     </h2>
     <p>
      下面我们来总结下注册流程：
     </p>
     <ul>
      <li>
       Register-Client
      </li>
      <li>
       1.加上相关的Soul注解，启动时将注册信息写入Distrupt队列
      </li>
      <li>
       2.Distrupt Consumer取数据，调用相关的注册中心服务进行数据注册（本篇中是Zookeeper）
      </li>
      <li>
       3.调用Zookeeper相关注册逻辑，将服务接口信息metadata和uridata写入Zookeeper中
      </li>
      <li>
       Register-Sever
      </li>
      <li>
       1.Zookeeper注册中心监听并取相关注册数据，将其放入Distrupt队列中
      </li>
      <li>
       2.Distrupt Consumer取数据，调用相关的metadata或者uridata的处理逻辑
      </li>
      <li>
       3.调用相关的Service注册逻辑，更新数据库，发布数据同步事件
      </li>
     </ul>
     <p>
      详细的流程图可以参考官网：https://dromara.org/zh/projects/soul/register-center-design/
     </p>
     <p>
      如果需要写一个其他类型的注册中心，因为使用SPI加载的原因，需要在下面的模块中的resources/META-INF/soul下的文件中填写新增的注册中心类型
     </p>
     <ul>
      <li>
       soul-register-client-xxxx
      </li>
      <li>
       soul-register-server-xxxx
      </li>
      <li>
       soul-admin
      </li>
      <li>
       soul-client-apache-dubbo(如果新增的client的注册中心刚开始不生效，可以在这加一下)
      </li>
     </ul>
     <h2 id="soul">
      Soul网关源码解析文章列表
     </h2>
     <p>
      对用Java写的高性能网关：
      <a href="https://github.com/dromara/soul">
       Soul
      </a>
      ,进行一波学习和研究，下面是相关的文章记录
     </p>
     <h3 id="_7">
      掘金
     </h3>
     <h4 id="_8">
      了解与初步运行
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917864624423436296">
        Soul网关源码解析（一） 概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917865804121767944">
        Soul网关源码解析（二）代码初步运行
       </a>
      </li>
     </ul>
     <h4 id="_9">
      请求处理流程解析
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917866538712334343">
        Soul网关源码解析（三）请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917867369909977102">
        Soul网关源码解析（四）Dubbo请求概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918575905962983438">
        Soul网关源码解析（五）请求类型探索
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918736260467015693">
        Soul网关源码解析（六）Sofa请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919348164944232455/">
        Soul网关源码解析（七）限流插件初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919774553241550855/">
        Soul网关源码解析（八）路由匹配初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920074307590684685/">
        Soul网关源码解析（九）插件配置加载初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920142348617777166">
        Soul网关源码解析（十）自定义简单插件编写
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596034171174925">
        Soul网关源码解析（十一）请求处理小结
       </a>
      </li>
     </ul>
     <h4 id="_10">
      数据同步解析
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6920596173925384206">
        Soul网关源码解析（十二）数据同步初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596028505178125">
        Soul网关源码解析（十三）Websocket同步数据-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920597298674302983">
        Soul网关源码解析（十四）HTTP数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920764643967238151">
        Soul网关源码解析（十五）Zookeeper数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921170233868845064">
        Soul网关源码解析（十六）Nacos数据同步示例运行
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921325882753695757/">
        Soul网关源码解析（十七）Nacos数据同步解析-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921495273122463751/">
        Soul网关源码解析（十八）Zookeeper数据同步初探-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921621915995996168/">
        Soul网关源码解析（十九）Nacos数据同步初始化修复-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921988280187617287/">
        Soul网关源码解析（二十）Websocket数据同步-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922301585288593416/">
        Soul网关源码解析（二十一）HTTP长轮询数据同步-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922584596810825735/">
        Soul网关源码解析（二十二）数据同步小结
       </a>
      </li>
     </ul>
     <h4 id="soul-client">
      Soul-Client模块
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6922643958455599111">
        Soul网关源码解析（二十三）SoulSpringMvcClient注解
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922722161702469640/">
        Soul网关源码解析（二十四）SoulDubboClient注解
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922745260435046408/">
        Soul网关源码解析（二十五）Soul-Client模块小结
       </a>
      </li>
     </ul>
     <h4 id="_11">
      总览
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6922960265663217678/">
        Soul网关源码解析（二十六）初步总览
       </a>
      </li>
     </ul>
     <h4 id="_12">
      番外
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6918947689564471309">
        Soul网关源码阅读番外篇（一） HTTP参数请求错误
       </a>
      </li>
     </ul>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
